home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcl
/
sptmbr16.lha
/
notes.text
< prev
next >
Wrap
Text File
|
1992-12-07
|
14KB
|
317 lines
These notes correspond to the "August 5 92 PCL" version of PCL.
This version of PCL is much closer than previous versions of PCL
to the metaobject protocol specified in "The Art of the Metaobject Protocol",
chapters 5 and 6, by Gregor Kiczales, Jim des Riveres, and Daniel G. Bobrow.
[Please read the file may-day-notes.text also. Most of that file still applies.]
Support for structures
You can use structure-class as a metaclass to create new classes.
Classes created this way create and evaluate defstruct forms which
have generated symbols for the structure accessors and constructor.
The generated symbols are used by the primary slot-value-using-class
methods and by the primary allocate-instance method for structures.
Defmethod optimizes usages of slot-value (when no user-defined
slot-value-using-class methods exist) into direct calls of the
generated symbol accessor, which the compiler can then optimize further.
Even when there are user-defined methods on slot-value-using-class,
PCL does a variety of optimizations.
If your implementation's version of the *-low.lisp file
contains definitions of certain structure functions (see the end of
low.lisp, cmu-low.lisp, lucid-low.lisp, and kcl-low.lisp), then
structure classes are supported for all defstructs. In this case,
structure classes are created automatically, when necessary.
New Classes:
structure-class
structure-object
slot-class
slot-object
structure-direct-slot-definition
structure-effective-slot-definition
Improvements to slot-access
Optimization for slot-value outsize of defmethod
Optimization for slot-value inside of defmethod, but not of a specialized parameter.
Optimizations that work even when there are :around methods
on slot-value-using-class.
New types:
`(class ,class-object)
`(class-eq ,class-object)
New specializer class: class-eq-specializer
Every class has a class-eq specializer which represents all
the direct instances of that class.
This is useful in *subtypep. For example, here is the way
generic-function initialization checks that the method-class is valid:
(and (classp method-class)
(*subtypep (class-eq-specializer method-class)
(find-class 'standard-method)))
If you want to define methods having class-eq specializers,
see "Initialization of method metaobjects". The default behavior of PCL
is to disallow this.
compute-applicable-methods-using-types
caching improvements
no magic-generic-functions list
This simplifies some things, but complicates some other things.
I wanted to support user-defined classes which are their own metaclass.
You can now do:
(defclass y (standard-class) ())
(defmethod validate-superclass ((c y) (sc standard-class)) t)
(defclass y (standard-class) () (:metaclass y))
method-function changes (see the comments for make-method-lambda, below)
final dfuns
-------------------------
gfs which obey AMOP ch 6
accessor-method-slot-definition
add-dependent
add-direct-method
add-direct-subclass
add-method
allocate-instance
compute-class-precedence-list
compute-default-initargs
compute-discriminating-function
compute-effective-slot-definition
[Note: compute-effective-slot-definition relys on
compute-effective-slot-definition-initargs and effective-slot-definition-class.
compute-effective-slot-definition-initargs is quite useful, but is not in
AMOP ch 6.]
compute-slots
direct-slot-definition-class
effective-slot-definition-class
ensure-class
ensure-class-using-class
ensure-generic-function
ensure-generic-function-using-class
eql-specializer-object
extract-lambda-list
extract-specializer-names
finalize-inheritance
find-method-combination
funcallable-standard-instance-access
{generic-function-method-class, generic-function-method-combination,
generic-function-lambda-list, generic-function-methods, generic-function-name}
intern-eql-specializer
make-instance
make-method-lambda
map-dependents
{method-function, method-generic-function, method-lambda-list,
method-specializers, method-qualifiers}
{class-default-initargs, class-direct-default-initargs, class-direct-slots,
class-direct-subclasses, class-direct-superclasses, class-finalized-p,
class-name, class-precedence-list, class-prototype, class-slots}
{slot-definition-allocation, slot-definition-initargs, slot-definition-initform,
slot-definition-initfunction, slot-definition-name, slot-definition-type}
{slot-definition-readers, slot-definition-writers}
{slot-definition-location}
remove-dependent
remove-direct-method
remove-direct-subclass
remove-method
set-funcallable-instance-function
(setf slot-value-using-class)
slot-boundp-using-class
slot-makunbound-using-class
specializer-direct-generic-functions
specializer-direct-methods
standard-instance-access
update-dependent
gfs which DO NOT obey AMOP ch 6
compute-applicable-methods
compute-applicable-methods-using-classes
Handles class-eq specializers without signalling an error.
But see "Initialization of method metaobjects", below.
compute-effective-method
Returns only one value.
generic-function-argument-precedence-order
Not yet defined. Can get this information from the arg-info structure.
generic-function-declarations
Not yet defined.
reader-method-class
Not yet defined. Some bootstrapping considerations are involved,
but adding this will not be very hard.
(setf class-name)
Currently just a writer method. Does not call reinitialize-instance or
(setf find-class).
(setf generic-function-name)
Currently just a writer method. Does not call reinitialize-instance.
writer-method-class
Not yet defined. Some bootstrapping considerations are involved,
but adding this will not be very hard.
---------------------------
Initialization of method metaobjects
The following methods are defined:
legal-qualifiers-p (method standard-method) qualifiers
legal-lambda-list-p (method standard-method) lambda-list
legal-specializers-p (method standard-method) specializers
legal-method-function-p (method standard-method) function
legal-documentation-p (method standard-method) documentation
legal-specializer-p (method standard-method) specializer
You can override them if you want.
The method for legal-specializers-p calls legal-specializer-p
on each specializer.
The method for legal-specializer-p allows any kind of specializer
when the variable *allow-experimental-specializers-p* is t
(this variable is initially nil).
---------------------------
Optimizations on slot-value
Outside of a defmethod when define-compiler-macro is not implemented
or the slot-name is not constant, or
Inside a defmethod when the slot-name is not a constant:
(1) no optimization of slot-value, slot-value-using-class is called.
slot-value-using-class has a special dfun, though, which calls
the slot's slot-definition-reader-function. This function is
a result of get-accessor-method-function.
Outside of a defmethod when define-compiler-macro is implemented and
the slot-name is a constant, or
Inside a defmethod when the slot-name is a constant but the object is
not either (the value of a parameter specialized to a subclass of structure-object
for which no user-defined slot-value-using-class methods apply at defmethod time),
or (the value of a parameter specialized to a subclass of standard-object).
(2) PCL arranges to call an automatically created generic function
which has one method: a reader method defined on class slot-object.
Inside a defmethod when the slot-name is a constant and the object
is (the value of a parameter specialized to a subclass of structure-object
for which no user-defined slot-value-using-class methods apply).
(3) The slot-value form is converted to a call of the structure slot's
accessor function, which the compiler can then optimize further.
Inside a defmethod when the slot-name is a constant and the object
is (the value of a parameter specialized to a subclass of standard-object).
(4) The access requires two arefs, a call to (typep x 'fixnum), and a call to eq,
in the best case. If user defined slot-value-using-class methods apply
at slot-value execution time, or the slot is unbound, the unoptimized
slot-value function (1) is called. This was in May Day PCL; what is new here
is that the PV (permutation vector) is looked up at defmethod load time
rather than at run time, if the effective method is cached.
Generic functions containing only accessor methods for which no user-defined
methods on slot-value-using-class apply and which involve only standard-classes:
A special dfun is called: one-class, two-class, one-index, or n-n.
These were all in May Day PCL.
Generic functions excluded by the above, which contain accessor methods:
In place of each accessor method's method-function, a function returned by
get-accessor-method-function is used.
get-accessor-method-function (gf type class slotd) ; type is reader, writer, or boundp.
If there is only one applicable method,
(This method will be the system supplied one)
the function that is returned is optimized for the current state of the
class. When the class changes, it must be recomputed.
otherwise,
a secondary dispatch function for slot-value-using-class is computed
(using what is known about the types of the arguments) and converted
into an accessor function.
get-secondary-dispatch-function (gf methods types &optional method-alist wrappers)
The types argument describes what is known about the types of the arguments.
Method-alist is used (when supplied) to do things like replace the
standard slot-value-using-class method function with a function optimized
for what is known about the arguments.
Wrappers (when supplied) means that the resulting function is guaranteed to
be called only whith those wrappers. Make-effective-method-function calls
the generic-function method-function-for-caching with method-alist and
wrappers to get a optimized method function. (PV lookup is done at the time
method-function-for-caching is called).
compute-applicable-methods: Here I tried to stick with the MOP.
The function cache-miss-values looks at the second value of the result of
compute-applicable-methods-using-classes. If this value is null, we aren't
supposed to cache the result of camuc. So we don't. Instead we cache a
result of (default-secondary-dispatch-function gf), which in turn calls
compute-applicable-methods each time it is called.
---------------------------
To do:
Problem: sometimes there is no need to call a gf's dfun: the emf that is invoked
can be cached in the caller's method closure.
1. In expand-defmethod-internal, optimize calls to generic-functions.
Add the support for this optimization.
2. [When CMUCL improves its setf handling, remove the comment in
the file macros.lisp beginning the line ";#+cmu (pushnew :setf *features*)"]
--------------
1) Generalize expand-defmethod-internal so that it can be used for non-defmethod
code. Maybe by (a) having a parameter that says whether it is being called by
defmethod, and (b) using the techniques used by the series package (shadowing
defun and some others, making the shadowed definitions call e-d-i, making it
easy for people to do the relevant package modifications)
2) Extending generic-functions by allowing the user at defgeneric time to supply
the name of a function which will be supplied (by the system) with a definition
which will return equivalent results to those returned by the generic function,
but which will (in some cases) have less checking than the generic function.
One-class, two-class, and one-index gf dfuns will map to a result of
get-optimized-std-accessor-method-function, checking gf dfuns will map to their
function, and any other dfun will remain the same.
3) Extending expand-defmethod-internal to optimize calls to generic-functions.
There are a variety of possibilities that need to be considered; one of them
will be to arrange to call the optimized functions produced by (2) when it
is known to be safe.
----------------------------------------------------------------------
----------------------------------------------------------------------
Here is how PCL uses the compiler at run time:
The only function that uses COMPILE is COMPILE-LAMBDA, defined in
low.lisp. See the code for some comments on how it works.
There are basically three uses of COMPILE-LAMBDA:
for creating discriminator functions (March 92 PCL creates discriminator
functions via lap code, September 16 PCL creates lisp code directly -
it is easier to read the Sept PCL code. Both versions invoke
COMPILE-LAMBDA in a similar manner.) Precompiling of discriminator
functions is done via the macro precompile-dfun-constructors.
for creating constructor functions (This is in Sept PCL only;
see fast-init.lisp for more information). Precompiling of
constructor functions is done via the macro precompile-iis-functions.
for creating the internal functions used by GET-FUNCTION (defined in
fngen.lisp. Refer to the September 16 92 PCL version because it has
better documentation on GET-FUNCTION.) Precompiling of these functions
is done by precompile-function-generators.
Precompiling of all three kinds of functions is done by
PRECOMPILILE-RANDOM-CODE-SEGMENTS (defined in low.lisp).
There are two uses of GET-FUNCTION (actually GET-FUNCTION1):
to create effective-method-functions, which are the functions which
actually call methods. Every method referred to by aan
effective-method-function is an applicable method as determined by
COMPUTE-APPLICABLE-METHODS (or maybe -USING-CLASSES or
-USING-TYPES). See the file combin.lisp.
to create secondary dispatch functions. These functions are called by
discriminator functions when the dfun couldn't determine the set of
applicable methods (when EQL specializers are present), and are
actually discriminator functions in themselves sometimes (these
are called dispatch dfuns). See the file methods.lisp.